package com.buaa.divinationmaster.core.utils;

import java.security.SecureRandom;
import java.util.Random;

/**
 * 随机数提供器
 * 为占卜算法提供高质量的随机数生成服务
 * 支持用户交互种子，确保占卜结果的个性化和不可预测性
 */
public class RandomProvider {
    
    private static final String TAG = "RandomProvider";
    
    private final Random random;
    private final boolean isSecure;
    private long currentSeed;
    
    // 静态实例（单例模式）
    private static volatile RandomProvider instance;
    
    /**
     * 私有构造函数
     * @param useSecureRandom 是否使用安全随机数生成器
     */
    private RandomProvider(boolean useSecureRandom) {
        this.isSecure = useSecureRandom;
        if (useSecureRandom) {
            this.random = new SecureRandom();
        } else {
            this.random = new Random();
        }
        this.currentSeed = System.currentTimeMillis();
        setSeed(this.currentSeed);
    }
    
    /**
     * 获取默认实例（使用安全随机数）
     */
    public static RandomProvider getInstance() {
        return getInstance(true);
    }
    
    /**
     * 获取实例
     * @param useSecureRandom 是否使用安全随机数
     */
    public static RandomProvider getInstance(boolean useSecureRandom) {
        if (instance == null) {
            synchronized (RandomProvider.class) {
                if (instance == null) {
                    instance = new RandomProvider(useSecureRandom);
                }
            }
        }
        return instance;
    }
    
    /**
     * 设置随机数种子
     * @param seed 种子值
     */
    public void setSeed(long seed) {
        this.currentSeed = seed;
        random.setSeed(seed);
    }
    
    /**
     * 基于用户交互生成种子
     * @param userInteractionSeed 用户交互种子
     */
    public void setSeedFromUserInteraction(long userInteractionSeed) {
        // 结合当前时间和用户交互，生成更复杂的种子
        long timeFactor = System.nanoTime();
        long combinedSeed = userInteractionSeed ^ timeFactor ^ (timeFactor >>> 32);
        setSeed(combinedSeed);
    }
    
    /**
     * 生成0到max-1范围内的随机整数
     * @param max 上限（不包含）
     * @return 随机整数
     */
    public int nextInt(int max) {
        if (max <= 0) {
            throw new IllegalArgumentException("最大值必须大于0");
        }
        return random.nextInt(max);
    }
    
    /**
     * 生成指定范围内的随机整数
     * @param min 下限（包含）
     * @param max 上限（不包含）
     * @return 随机整数
     */
    public int nextInt(int min, int max) {
        if (min >= max) {
            throw new IllegalArgumentException("最小值必须小于最大值");
        }
        return min + nextInt(max - min);
    }
    
    /**
     * 生成随机长整数
     * @return 随机长整数
     */
    public long nextLong() {
        return random.nextLong();
    }
    
    /**
     * 生成0.0到1.0之间的随机浮点数
     * @return 随机浮点数
     */
    public float nextFloat() {
        return random.nextFloat();
    }
    
    /**
     * 生成0.0到1.0之间的随机双精度浮点数
     * @return 随机双精度浮点数
     */
    public double nextDouble() {
        return random.nextDouble();
    }
    
    /**
     * 生成随机布尔值
     * @return 随机布尔值
     */
    public boolean nextBoolean() {
        return random.nextBoolean();
    }
    
    /**
     * 生成指定概率的布尔值
     * @param probability 概率（0.0到1.0）
     * @return 是否命中概率
     */
    public boolean nextBoolean(double probability) {
        if (probability < 0.0 || probability > 1.0) {
            throw new IllegalArgumentException("概率必须在0.0到1.0之间");
        }
        return nextDouble() < probability;
    }
    
    /**
     * 模拟抛硬币
     * @return true表示正面，false表示反面
     */
    public boolean coinFlip() {
        return nextBoolean();
    }
    
    /**
     * 模拟投掷骰子
     * @param sides 骰子面数
     * @return 1到sides之间的随机数
     */
    public int rollDice(int sides) {
        if (sides <= 0) {
            throw new IllegalArgumentException("骰子面数必须大于0");
        }
        return nextInt(sides) + 1;
    }
    
    /**
     * 从数组中随机选择一个元素
     * @param array 数组
     * @param <T> 元素类型
     * @return 随机选择的元素
     */
    public <T> T choice(T[] array) {
        if (array == null || array.length == 0) {
            throw new IllegalArgumentException("数组不能为空");
        }
        return array[nextInt(array.length)];
    }
    
    /**
     * Fisher-Yates洗牌算法
     * @param array 待洗牌的数组
     * @param <T> 数组元素类型
     */
    public <T> void shuffle(T[] array) {
        if (array == null || array.length <= 1) {
            return;
        }
        
        for (int i = array.length - 1; i > 0; i--) {
            int j = nextInt(i + 1);
            // 交换元素
            T temp = array[i];
            array[i] = array[j];
            array[j] = temp;
        }
    }
    
    /**
     * 生成指定长度的随机字节数组
     * @param length 长度
     * @return 随机字节数组
     */
    public byte[] nextBytes(int length) {
        if (length <= 0) {
            throw new IllegalArgumentException("长度必须大于0");
        }
        byte[] bytes = new byte[length];
        random.nextBytes(bytes);
        return bytes;
    }
    
    /**
     * 获取当前种子值
     * @return 当前种子
     */
    public long getCurrentSeed() {
        return currentSeed;
    }
    
    /**
     * 是否使用安全随机数生成器
     * @return 是否安全
     */
    public boolean isSecure() {
        return isSecure;
    }
    
    /**
     * 重置随机数生成器（使用当前时间作为种子）
     */
    public void reset() {
        setSeed(System.currentTimeMillis());
    }
    
    /**
     * 测试随机数分布质量（仅用于调试）
     * @param sampleSize 样本大小
     * @return 分布统计信息
     */
    public String testDistribution(int sampleSize) {
        if (sampleSize <= 0) {
            return "样本大小无效";
        }
        
        int[] counts = new int[10]; // 将0-1范围分为10个区间
        for (int i = 0; i < sampleSize; i++) {
            double value = nextDouble();
            int bucket = Math.min(9, (int) (value * 10));
            counts[bucket]++;
        }
        
        StringBuilder result = new StringBuilder("随机数分布测试 (样本: " + sampleSize + ")\n");
        for (int i = 0; i < counts.length; i++) {
            double percentage = (counts[i] * 100.0) / sampleSize;
            result.append(String.format("区间[%.1f-%.1f]: %d (%.1f%%)\n", 
                    i * 0.1, (i + 1) * 0.1, counts[i], percentage));
        }
        
        return result.toString();
    }
    
    @Override
    public String toString() {
        return "RandomProvider{" +
                "isSecure=" + isSecure +
                ", currentSeed=" + currentSeed +
                ", class=" + random.getClass().getSimpleName() +
                '}';
    }
}
